package com.ruoyi.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.util.JSONPObject;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.Map;

/**
 * Json序列化工具
 */

public class JsonUtil {

    private static final ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 忽略不存在的属性
        mapper.disable(SerializationFeature.WRITE_NULL_MAP_VALUES);
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
    }

    public static ObjectMapper getObjectMapper() {
        return mapper;
    }

    /**
     * 反序列化，泛型方法
     *
     * @return 返回目标对象
     */
    public static <T> T deserialize(String str, Class<T> clazz) {
        try {
            return mapper.readValue(str, clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 反序列化，泛型方法
     *
     * @return 返回目标对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T deserialize(String str, TypeReference<T> typeRef) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        try {
            return (T) mapper.readValue(str, typeRef);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T deserialize(String str, JavaType javaType) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        try {
            return (T) mapper.readValue(str, javaType);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T deserialize(JsonNode jsonNode, Class<T> clazz) {
        if (jsonNode == null) {
            return null;
        }
        try {
            return (T) mapper.treeToValue(jsonNode, clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 序列化
     *
     * @return 序列化String
     */
    public static String serialize(Object object) {
        try {
            return mapper.writeValueAsString(object);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 输出JSONP格式数据.
     */
    public static String serializeJsonP(String functionName, Object object) {
        return serialize(createJsonP(functionName, object));
    }

    public static JSONPObject createJsonP(String functionName, Object object) {
        return new JSONPObject(functionName, object);
    }

    public static <T> T convertValue(JsonNode node, JavaType javaType) {
        try {
            return mapper.convertValue(node, javaType);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 构造Collection类型.
     */
    @SuppressWarnings("rawtypes")
    public static JavaType contructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass) {
        return mapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
    }

    /**
     * 构造Map类型.
     */
    @SuppressWarnings("rawtypes")
    public static JavaType contructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
        return mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
    }

    /**
     * 当JSON里只含有Bean的部分属性时，更新一个已存在Bean，只覆盖该部分的属性.
     */
    public static void update(String jsonString, Object object) throws Exception {
        mapper.readerForUpdating(object).readValue(jsonString);
    }

    public static JsonNode toJsonNode(String jsonStr, String fieldName) throws Exception {
        JsonNode jsonNode = mapper.readTree(jsonStr);
        if (jsonNode == null) {
            return null;
        }

        return jsonNode.get(fieldName);
    }

    /**
     * 取json传里面的某个属性值。
     *
     * @param jsonStr   JSON字符串
     * @param fieldName 熟悉名称
     *                  对象为空时，底层抛出异常时，均会封装成RuntimeException抛出
     * @return Integer 该属性名称所对应的值
     */
    public static Integer getIntField(String jsonStr, String fieldName) {
        try {
            JsonNode nameNode = toJsonNode(jsonStr, fieldName);
            if (nameNode != null) {
                return nameNode.asInt();
            }

            return null;
        } catch (Exception e) {
            String msg = String.format("Failed to parse json %s", jsonStr);
            throw new RuntimeException(msg, e);
        }
    }

    /**
     * 取json传里面的某个属性值。
     *
     * @param jsonStr   JSON字符串
     * @param fieldName 属性名称
     *                  对象为空时，底层抛出异常时，均会封装成RuntimeException抛出
     * @return String 该属性名称所对应的值
     */
    public static String getStringField(String jsonStr, String fieldName) {
        try {
            JsonNode nameNode = toJsonNode(jsonStr, fieldName);
            if (nameNode != null) {
                return nameNode.asText();
            }

            return null;
        } catch (Exception e) {
            String msg = String.format("Failed to parse json %s", jsonStr);
            throw new RuntimeException(msg, e);
        }
    }

    /**
     * 取json传里面的某个属性值。
     *
     * @param jsonStr   JSON字符串
     * @param fieldName 属性名称
     *                  对象为空时，底层抛出异常时，均会封装成RuntimeException抛出
     * @return Long 该属性名称所对应的值
     */
    public static Long getLongField(String jsonStr, String fieldName) {
        try {
            JsonNode nameNode = toJsonNode(jsonStr, fieldName);
            if (nameNode != null) {
                return nameNode.asLong();
            }

            return null;
        } catch (Exception e) {
            String msg = String.format("Failed to parse json %s", jsonStr);
            throw new RuntimeException(msg, e);
        }
    }

    /**
     * 取json传里面的某个属性值。
     *
     * @param jsonStr   JSON字符串
     * @param fieldName 属性名称
     *                  对象为空时，底层抛出异常时，均会封装成RuntimeException抛出
     * @return Boolean 该属性名称所对应的值
     */
    public static Boolean getBooleanField(String jsonStr, String fieldName) {
        try {
            JsonNode nameNode = toJsonNode(jsonStr, fieldName);
            if (nameNode != null) {
                return nameNode.asBoolean();
            }
            return null;
        } catch (Exception e) {
            String msg = String.format("Failed to parse json %s", jsonStr);
            throw new RuntimeException(msg, e);
        }
    }

    /**
     * 取json传里面的某个属性值。
     *
     * @param jsonStr   JSON字符串
     * @param fieldName 属性名称
     *                  对象为空时，底层抛出异常时，均会封装成RuntimeException抛出
     * @return Double 该属性名称所对应的值
     */
    public static Double getDoubleField(String jsonStr, String fieldName) {
        try {
            JsonNode nameNode = toJsonNode(jsonStr, fieldName);
            if (nameNode != null) {
                return nameNode.asDouble();
            }
            return null;
        } catch (Exception e) {
            String msg = String.format("Failed to parse json %s", jsonStr);
            throw new RuntimeException(msg, e);
        }
    }


//    /**
//     * 精简一个object类型的json字符串，去掉里面的注释与空格
//     * 如果不符合json规则（带注释），将直接返回原来的字符串。
//     * <p>
//     * 注意：不支持多行注释与单行注释嵌套的情况 ，存在字符串篡改的可能性，只能用于信任数据的处理。
//     *
//     * @param json json字符串 举例{"name":"name", \n //年龄\n, "age":18}
//     * @return 返回精简后的字符串 {"name":"name","age":18}
//     */
//    public static String simplifyJsonString(String json) {
//        String res = json;
//        String tmp = json;
//        try {
//
//            tmp = tmp.replaceAll("//.*[\\n|\\r\\n]", ""); //去掉单行注释
//            tmp = tmp.replaceAll("/\\*[\\s\\S]*\\*/", ""); //去掉多行注释
//
//            JsonNode node = mapper.readTree(tmp);
//            res = node.toString();
//        } catch (Exception e) {
//            logger.error("解析json失败,json:{}", json, e);
//        }
//        return res;
//    }
}
